From: mwilli2@equilibrium.research Date: Tue, 28 Sep 2004 14:47:51 +0000 (+0000) Subject: bitkeeper revision 1.1159.1.191 (41597997cc5ZJzvh6XLLSIhJ9hLEnA) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~17400^2~560 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=e52d6a8915cc5b73701d32ffaa13bcb11c349d00;p=xen.git bitkeeper revision 1.1159.1.191 (41597997cc5ZJzvh6XLLSIhJ9hLEnA) Initial support for automatic management of non-phy block devices. --- diff --git a/.rootkeys b/.rootkeys index 6ecc463f9b..804e8a419d 100644 --- a/.rootkeys +++ b/.rootkeys @@ -314,6 +314,8 @@ 4124b308O8yPHMKbj4YPR_grPGZmdA tools/check/chk 401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile 401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README +41597996VhTbNuHbuscYSfRb-WR6fA tools/examples/block-enbd +41597996GHP2_yVih2UspXh328fgMQ tools/examples/block-file 405ff55dawQyCHFEnJ067ChPRoXBBA tools/examples/init.d/xend 40278d94cIUWl2eRgnwZtr4hTyWT1Q tools/examples/init.d/xendomains 40ee75a9xFz6S05sDKu-JCLqyVTkDA tools/examples/network @@ -453,6 +455,7 @@ 40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py 4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py 40c9c468SNuObE_YWARyS0hzTPSzKg tools/python/xen/xend/Args.py +41597996WNvJA-DVCBmc0xU9w_XmoA tools/python/xen/xend/Blkctl.py 40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py 40c9c468U8EVl0d3G--8YXVg6VJD3g tools/python/xen/xend/EventTypes.py 40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py diff --git a/tools/examples/block-enbd b/tools/examples/block-enbd new file mode 100644 index 0000000000..cfae6288b2 --- /dev/null +++ b/tools/examples/block-enbd @@ -0,0 +1,33 @@ +#!/bin/sh + +# Usage: block-enbd [bind server ctl_port |unbind node] +# +# The file argument to the bind command is the file we are to bind to a +# loop device. We print the path to the loop device node to stdout. +# +# The node argument to unbind is the name of the device node we are to +# unbind. +# +# This assumes you're running a correctly configured server at the other end! + +case $1 in + bind) + for dev in /dev/nd*; do + if nbd-client $2:$3 $dev; then + echo $dev + exit 0 + fi + done + exit 1 + ;; + + unbind) + nbd-client -d $2 + exit 0 + ;; + + *) + echo 'Unknown command: ' $1 + echo 'Valid commands are: bind, unbind' + exit 1 +esac diff --git a/tools/examples/block-file b/tools/examples/block-file new file mode 100644 index 0000000000..362b1faee5 --- /dev/null +++ b/tools/examples/block-file @@ -0,0 +1,31 @@ +#!/bin/sh + +# Usage: block_loop [bind file|unbind node] +# +# The file argument to the bind command is the file we are to bind to a +# loop device. We print the path to the loop device node to stdout. +# +# The node argument to unbind is the name of the device node we are to +# unbind. + +case $1 in + bind) + for dev in /dev/loop*; do + if losetup $dev $2; then + echo $dev + exit 0 + fi + done + exit 1 + ;; + + unbind) + losetup -d $2 + exit 0 + ;; + + *) + echo 'Unknown command: ' $1 + echo 'Valid commands are: bind, unbind' + exit 1 +esac diff --git a/tools/examples/xend-config.sxp b/tools/examples/xend-config.sxp index f710a54529..ee5dbbc0a3 100644 --- a/tools/examples/xend-config.sxp +++ b/tools/examples/xend-config.sxp @@ -21,3 +21,9 @@ # virtual interfaces. Specify 'yes' or 'no'. (vif-antispoof no) +# Setup script for file-backed block devices +(block-file block-file) + +# Setup script for enbd-backed block devices +(block-enbd block-enbd) + diff --git a/tools/python/xen/xend/Blkctl.py b/tools/python/xen/xend/Blkctl.py new file mode 100644 index 0000000000..a5bda19470 --- /dev/null +++ b/tools/python/xen/xend/Blkctl.py @@ -0,0 +1,42 @@ +"""Xend interface to block control scripts. +""" +import os +import os.path +import sys +import string + +from xen.xend import XendRoot +xroot = XendRoot.instance() + +"""Where network control scripts live.""" +SCRIPT_DIR = xroot.block_script_dir + +def block(op, type, dets, script=None): + """Call a block control script. + Xend calls this with op 'bind' when it is about to export a block device + (other than a raw partition). The script is called with unbind when a + device is no longer in use and should be removed. + + @param op: operation (start, stop, status) + @param type: type of block device (determines the script used) + @param dets: arguments to the control script + @param script: block script name + """ + + if op not in ['bind', 'unbind']: + raise ValueError('Invalid operation:' + op) + + # Special case phy devices - they don't require any (un)binding + if type == 'phy': + return dets + + if script is None: + script = xroot.get_block_script(type) + script = os.path.join(SCRIPT_DIR, script) + args = [op] + string.split(dets, ':') + args = ' '.join(args) + out = os.popen(script + ' ' + args) + + output = out.readline() + out.close() + return string.rstrip(output) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 8a8af83c10..7f789a48f7 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -33,6 +33,8 @@ xend = server.SrvDaemon.instance() from XendError import VmError +from server.blkif import blkdev_name_to_number + """The length of domain names that Xen can handle. The names stored in Xen itself are not used for much, and xend can handle domain names of any length. @@ -90,61 +92,6 @@ def shutdown_reason(code): """ return shutdown_reasons.get(code, "?") -def blkdev_name_to_number(name): - """Take the given textual block-device name (e.g., '/dev/sda1', - 'hda') and return the device number used by the OS. """ - - if not re.match( '^/dev/', name ): - n = '/dev/' + name - else: - n = name - - try: - return os.stat(n).st_rdev - except: - pass - - # see if this is a hex device number - if re.match( '^(0x)?[0-9a-fA-F]+$', name ): - return string.atoi(name,16) - - return None - -def lookup_raw_partn(name): - """Take the given block-device name (e.g., '/dev/sda1', 'hda') - and return a dictionary { device, start_sector, - nr_sectors, type } - device: Device number of the given partition - start_sector: Index of first sector of the partition - nr_sectors: Number of sectors comprising this partition - type: 'Disk' or identifying name for partition type - """ - - n = blkdev_name_to_number(name) - if n: - return [ { 'device' : n, - 'start_sector' : long(0), - 'nr_sectors' : long(1L<<63), - 'type' : 'Disk' } ] - else: - return None - -def lookup_disk_uname(uname): - """Lookup a list of segments for a physical device. - - @param uname: name of the device in the format \'phy:dev\' for a physical device - @type uname: string - @return: list of extents that make up the named device - @rtype: [dict] - """ - ( type, d_name ) = string.split( uname, ':' ) - - if type == "phy": - segments = lookup_raw_partn( d_name ) - else: - segments = None - return segments - def make_disk(vm, config, uname, dev, mode, recreate=0): """Create a virtual disk device for a domain. @@ -156,18 +103,12 @@ def make_disk(vm, config, uname, dev, mode, recreate=0): @return: deferred """ idx = vm.next_device_index('vbd') - segments = lookup_disk_uname(uname) - if not segments: - raise VmError("vbd: Segments not found: uname=%s" % uname) - if len(segments) > 1: - raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname) - segment = segments[0] # todo: The 'dev' should be looked up in the context of the domain. vdev = blkdev_name_to_number(dev) if not vdev: raise VmError("vbd: Device not found: uname=%s dev=%s" % (uname, dev)) ctrl = xend.blkif_create(vm.dom, recreate=recreate) - return ctrl.attachDevice(idx, config, vdev, mode, segment, recreate=recreate) + return ctrl.attachDevice(idx, config, uname, vdev, mode, recreate=recreate) def vif_up(iplist): """send an unsolicited ARP reply for all non link-local IP addresses. diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index d9c6c80012..8f188b5d69 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -46,6 +46,9 @@ class XendRoot: """Where network control scripts live.""" network_script_dir = "/etc/xen/scripts" + """Where block control scripts live.""" + block_script_dir = "/etc/xen/scripts" + logfile_default = "/var/log/xend.log" loglevel_default = 'DEBUG' @@ -260,6 +263,9 @@ class XendRoot: def get_xend_address(self): return self.get_config_value('xend-address', '') + def get_block_script(self, type): + return self.get_config_value('block-%s' % type, '') + def get_network_script(self): return self.get_config_value('network-script', 'network') diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 2cd5f1b2b3..69f9431f48 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -5,9 +5,13 @@ from twisted.internet import defer from xen.xend import sxp +from xen.xend import Blkctl from xen.xend.XendLogging import log -from xen.xend.XendError import XendError +from xen.xend.XendError import XendError, VmError +import os +import re +import string import channel import controller from messages import * @@ -257,6 +261,11 @@ class BlkDev(controller.SplitDev): val.append(['uname', self.uname]) return val + def unbind(self): + log.debug("Unbinding block dev (type %s) from %s" + % (self.type, self.node)) + Blkctl.block('unbind', self.type, self.node) + def destroy(self, change=0): """Destroy the device. If 'change' is true notify the front-end interface. @@ -266,6 +275,7 @@ class BlkDev(controller.SplitDev): d = self.send_be_vbd_destroy() if change: d.addCallback(lambda val: self.interfaceChanged()) + d.addCallback(lambda val: self.unbind()) def interfaceChanged(self): """Tell the back-end to notify the front-end that a device has been @@ -345,7 +355,47 @@ class BlkDev(controller.SplitDev): backend.writeRequest(msg, response=d) return d - + +def blkdev_name_to_number(name): + """Take the given textual block-device name (e.g., '/dev/sda1', + 'hda') and return the device number used by the OS. """ + + if not re.match( '^/dev/', name ): + n = '/dev/' + name + else: + n = name + + try: + return os.stat(n).st_rdev + except Exception, e: + print "blkdev_name_to_number> exception looking up device number for %s: %s" % (name, e) + pass + + # see if this is a hex device number + if re.match( '^(0x)?[0-9a-fA-F]+$', name ): + return string.atoi(name,16) + + return None + +def lookup_raw_partn(name): + """Take the given block-device name (e.g., '/dev/sda1', 'hda') + and return a dictionary { device, start_sector, + nr_sectors, type } + device: Device number of the given partition + start_sector: Index of first sector of the partition + nr_sectors: Number of sectors comprising this partition + type: 'Disk' or identifying name for partition type + """ + + n = blkdev_name_to_number(name) + if n: + return [ { 'device' : n, + 'start_sector' : long(0), + 'nr_sectors' : long(1L<<63), + 'type' : 'Disk' } ] + else: + return None + class BlkifController(controller.SplitController): """Block device interface controller. Handles all block devices for a domain. @@ -386,7 +436,7 @@ class BlkifController(controller.SplitController): self.devices[idx] = dev return dev - def attachDevice(self, idx, config, vdev, mode, segment, recreate=0): + def attachDevice(self, idx, config, uname, vdev, mode, recreate=0): """Attach a device to the specified interface. On success the returned deferred will be called with the device. @@ -403,10 +453,30 @@ class BlkifController(controller.SplitController): @return: deferred @rtype: Deferred """ + if not recreate: + # Split into type and type-specific details (which are passed to the + # type-specific control script). + type, dets = string.split(uname, ':', 1) + # Special case: don't bother calling a script for phy. Could + # alternatively provide a "do nothing" script for phy devices... + node = Blkctl.block('bind', type, dets) + + segments = lookup_raw_partn(node) + + if not segments: + raise VmError("vbd: Segments not found: uname=%s" % uname) + if len(segments) > 1: + raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname) + + segment = segments[0] + dev = self.addDevice(idx, config, vdev, mode, segment) + if recreate: d = defer.succeed(dev) else: + dev.node = node + dev.type = type d = dev.attach() return d